Load Libraries and Data

library(tidyverse)
library(sf)
library(lubridate)
library(tidytext)
library(scales)
library(viridis)

# Load the single, final clean file
inspections <- read_csv("data/inspections_clean.csv")

EDA Report

The goal of this section is to understand the overall shape of our data.

Basic Plots

# Inspections by City
ggplot(inspections, aes(x = city_source)) + geom_bar() + labs(title = "Inspections by City") + theme_minimal()


#Outcomes
ggplot(inspections, aes(x = inspection_outcome)) + 
  geom_bar() +
  scale_y_continuous(labels = label_comma()) +
  labs(title = "Outcomes")


#Risks
ggplot(inspections, aes(x = risk_level_standard)) + 
  labs(title = "Risks") + 
  scale_y_continuous(labels = label_comma()) + 
  geom_bar()

  
#Time Range of the Data
ggplot(inspections, aes(x = inspection_date)) + geom_histogram(bins = 50) + 
scale_y_continuous(labels = label_comma()) +
  labs(title = "Distribution of Inspections Over Time", x = "Date", y = "Count")

Our initial phase of exploratory data analysis (EDA) focused on understanding the overall shape, distribution, and integrity of our combined 1.4 million-row dataset. This initial analysis confirms our combined dataset is large, usable, and modern, but critically imbalanced.

Plot 1: Inspections by City This bar chart shows the total number of inspections contributed by each city. The key finding here is that our dataset is heavily imbalanced. Boston is the source of a large majority of our data (over 750,000 rows), while Chicago and New York are similarly sized, and San Francisco is our smallest dataset.

This is a critical finding because it confirms that we cannot use raw counts to compare cities. All future city-to-city comparisons must be based on proportions or percentages (using position = “fill”) to be fair and accurate.

Plot 2: Overall Inspection Outcomes This plot shows the distribution of our newly-created inspection_outcome column across the entire dataset. While “Fail” and “Pass” are the most frequent outcomes, this plot is heavily skewed by the disproportionate size of the Boston data. We can’t draw any real conclusions from this yet. Its main purpose for now is to confirm that our case_when() logic successfully categorized all 1.4 million rows.

Plot 3: Distribution of Inspections Over Time This histogram is one of our most important initial plots. It confirms two things:

The data is recent: The vast majority of our inspections occurred from roughly 2005 to the present, which is excellent for answering our research questions about modern trends.

We have “bad data” to filter: The plot clearly identifies a small cluster of “bad data” (placeholder dates from 1900) that we must filter out before conducting any time-series analysis. The warning message also confirmed that a negligible number of rows (~6,400, or <0.5%) were dropped due to missing dates, which will not impact our analysis.

City Comparisons

#Outcomes by City
ggplot(inspections, aes(x = city_source, fill = inspection_outcome)) + 
  geom_bar(position = "fill") + 
  labs(title = "Outcomes by City", y = "Proportion")


#Risk Level by City
ggplot(inspections, aes(x = city_source, fill = risk_level_standard)) + 
  geom_bar(position = "fill") +
    labs(title = "Risk Level by City", y = "Proportion")


#Score Distributions
ggplot(inspections, aes(x = city_source, y = inspection_score)) + 
  geom_boxplot() +
    labs(title = "Score Distributions")


ggplot(inspections, aes(x = inspection_outcome, y = inspection_score, fill = city_source)) +
  geom_boxplot() + 
  facet_wrap(~ city_source) + #show how our standardized Pass/Fail categories line up with the numeric scores
    labs(title = "Score Distributions by City (Standardized")

After establishing the overall shape of our data, we drilled down to compare the four cities. This is where our standardization efforts provide their first major insights, revealing that the cities have vastly different inspection profiles.

Plot 4: Proportions of Outcomes by City This plot directly compares the pass/fail rates for each city. We found that Boston and San Francisco have the highest proportion of “Fail” outcomes. In contrast, New York’s profile is dominated by “Pass” (reflecting their ‘A’ grades) and “Pending” results. This confirms that each city’s grading system is unique and that our inspection_outcome column successfully captured these differences.

Plot 5: Proportion of Risk Level by City This is one of the most striking findings so far. Chicago and New York log a dramatically higher proportion of “High Risk” violations than Boston and San Francisco. In Chicago, “High Risk” appears to be the most common category, while in Boston, “Low Risk” is dominant. This may reflect different public health definitions of “risk” or different areas of focus for each city’s inspectors.

Plot 6 & 7: Score Distributions These two plots (which we’ve combined for analysis) confirm our inspection_outcome logic and reveal the inverted nature of the scoring systems.

NYC uses a demerit system: A lower score is better. Our plot shows that “Pass” (Grade A) has the lowest scores, while “Fail” (Grade C) has the highest.

SF uses a points-based system: A higher score is better. Our plot confirms this, showing “Pass” (90+) has the highest scores and “Fail” (71-85) has lower scores.

This analysis validates our standardization and proves that the two scoring systems are direct opposites.

Exploring Fail Rates Over Time


# Create a summary table
fails_by_year <- inspections |>
  filter(inspection_date > "2000-01-01") |> # filter out 'bad' dates
  mutate(year = year(inspection_date)) |>
  group_by(city_source, year) |>
  summarize(
    fail_rate = mean(inspection_outcome == "Fail", na.rm = TRUE),
    total_inspections = n()
  ) |>
  filter(total_inspections > 100) # Remove years with tiny data

# Plot the summary
ggplot(fails_by_year, aes(x = year, y = fail_rate, color = city_source)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  scale_y_continuous(labels = label_percent()) +     # format y-axis as percentage
  scale_color_viridis_d() +                         # add better colors
  labs(
    title = "Fail Rate Over Time by City", 
    y = "Proportion of Fails",                      # <-- Fix y-axis label
    x = "Year",
    color = "City"                                  # <-- Fix legend title
  )


# Least Successful zipcodes in each city in the dataset
fails_by_zip <- inspections |>
  filter(inspection_date > "2000-01-01") |> # Good idea to filter bad dates
  group_by(city_source, zip_code) |>
  summarize(
    fail_rate = mean(inspection_outcome == "Fail", na.rm = TRUE),
    total_inspections = n()
  ) |>
  filter(total_inspections > 100) |> # Only include zips with 100+ inspections
  ungroup()

# Summary table for zip codes
fails_by_zip |>
  group_by(city_source) |>      # Group by city
  top_n(3, fail_rate) |>        # Find the top 3 *within* that city
  ungroup() |>
  
  # This 'reorder_within' is a special trick to make facets work
  mutate(
    zip_code = tidytext::reorder_within(zip_code, fail_rate, city_source)
  ) |>

  ggplot(aes(x = zip_code, y = fail_rate, fill = city_source)) +
  geom_col() +
  tidytext::scale_x_reordered() + # This makes the labels plot correctly
  facet_wrap(~ city_source, scales = "free") + #Create 4 separate charts
  coord_flip() +
  labs(
    title = "Top 3 Zip Codes with Highest Fail Rate by City",
    x = "Zip Code",
    y = "Fail Rate"
  ) +
  theme(legend.position = "none")

Following our city-level comparisons, we moved into our first multivariate analysis to answer our research questions about where and when violations occur.

Plot 8: Fail Rate Over Time by City This line graph plots the proportion (percentage) of “Fail” outcomes for each city, from 2008 to 2025. This is our most significant finding so far:

Dramatically Different Systems: The definition of a “Fail” is clearly not standardized.

Boston: Has a very high and consistent “Fail” rate, hovering around 60% for the entire 15-year period. This strongly suggests that Boston’s result column logs a “Fail” for even minor infractions, making it a very common outcome.

Chicago: Shows a positive trend. Its fail rate has steadily decreased from ~25% in 2010 to a stable ~18-20% in recent years.

New York: Has an extremely low fail rate, consistently staying below 10%. This aligns perfectly with their “Grade A” system, where a ‘C’ (which we mapped to “Fail”) is rare.

San Francisco: Appears to have a fail rate of around 30%, landing between Boston and the other two cities.

Plot 9: Top 3 Worst Zip Codes by City This bar chart was intended to find the “worst” zip codes across the entire dataset. We have now successfully identified specific geographic areas of concern for each city:

Boston: 02119-3212, 02120

Chicago: 60827, 60619

New York: 11436, 11428

San Francisco: 94134, 94118

Boston Zipcodes Map

There are 43 zip codes in the City of Boston

Top Violations Overall

top_bigrams <- inspections |>
  sample_frac(0.5) |>  # Taking a 50% random sample to reduce memory load
  filter(!is.na(violation_desc)) |>
  unnest_tokens(bigram, violation_desc, token = "ngrams", n = 2) |>
  count(bigram, sort = TRUE)

# Plot the top 20
top_bigrams |>
  top_n(20) |>
  ggplot(aes(x = reorder(bigram, n), y = n)) +
  geom_col() +
  coord_flip() +
  labs(
    title = "Top 20 Most Common Violation Phrases (50% Sample)",
    x = "Violation Phrase (Bigram)",
    y = "Total Count"
  )

This plot, despite successfully processing the text, shows that the most common phrases across all cities are generic, high-frequency functional words like ‘food contact’ and ‘non food’. We do not see specific issues like ‘rodent’ or ‘improper temperature’ in the top 20, confirming that these key issues are diluted by common, general phrases. This validates our next step to use manual keyword searching to group thousands of unique violations into meaningful categories.

Days of the week that see the most inspections

inspections |> 
  mutate(wday = wday(inspection_date, label = TRUE)) |> 
  count(wday) |>
  ggplot(aes(wday, n)) +
  geom_col() +
  scale_y_continuous(labels = label_comma()) +
  labs(title = "Inspections by Day of Week")

This analysis confirms that inspection frequency is heavily skewed toward weekdays, with a slight peak on Tuesday. The low counts on Sunday and Saturday suggest that weekend inspections are rare or reserved only for specific facilities.

Inspection Frequency per Restaurant

ggplot(inspections |> count(restaurant_name), aes(n)) +
  geom_histogram(breaks = seq(0, 50, by = 1), color="black", fill="skyblue") +
  labs(title="Distribution of Inspections per Restaurant", x="Number of Inspections", y="Number of Restaurants")

The tallest bar shows that nearly 10,000 restaurants have been inspected only once (or close to once) during the dataset’s time frame. The number of restaurants drops off steeply for businesses inspected just 2, 3, or 4 times. The long, flat tail on the right is highly significant. While most businesses are inspected infrequently, a small but consistent number of restaurants are inspected 20, 30, 40, or even 50+ times. This may be due to routine inspections happening, but this is unlikely for the time period covered in our data. This coudl also suggest that the inspection system is effectively using a risk-based approach. Restaurants that fail or have serious violations are likely pushed into re-inspection cycles or receive more frequent routine inspections. Conversely, successful restaurants are inspected less often, freeing up resources.

Answering Research Questions

Seun’s Analysis

Categorize Violations

inspections_categorized <- inspections |>
  mutate(
    violation_category = case_when(
      str_detect(violation_desc, "mice|rodent|droppings|insects|pests|harborage") ~ "Pest Control",
      str_detect(violation_desc, "temperature|cool|hot-holding|cold-holding|refrigerat") ~ "Food Temperature",
      str_detect(violation_desc, "wash|sanitiz|clean|wiping cloths|dishwashing") ~ "Sanitation & Cleaning",
      str_detect(violation_desc, "hand wash|hygiene|no hair|bare hand") ~ "Employee Hygiene",
      str_detect(violation_desc, "contaminat|cross-contamination|raw|covered|protect") ~ "Cross-Contamination",
      str_detect(violation_desc, "floor|wall|ceiling|plumbing|ventilation|garbage") ~ "Facility/Maintenance",
      TRUE ~ "Other"
    )
  )

#Check new categories
inspections_categorized |>
  count(violation_category, sort = TRUE)

Categorize Restaurants

inspections_categorized <- inspections_categorized |>
  mutate(
    # Create one combined description column to search
    desc_all = coalesce(cuisine_description, facility_type, descript) |> tolower(),
    
    restaurant_category = case_when(
      str_detect(desc_all, "pizza|pizzeria") ~ "Pizza",
      str_detect(desc_all, "sushi|japanese") ~ "Sushi/Japanese",
      str_detect(desc_all, "coffee|cafe|bakery|donut") ~ "Coffee/Bakery",
      str_detect(desc_all, "mexican|taco") ~ "Mexican",
      str_detect(desc_all, "chinese") ~ "Chinese",
      str_detect(desc_all, "sandwich|deli|sub") ~ "Sandwich/Deli",
      str_detect(desc_all, "bar|tavern|pub") ~ "Bar/Pub",
      str_detect(desc_all, "restaurant|american") ~ "Restaurant (General)",
      str_detect(desc_all, "school|grocery|market|caterer|kitchen") ~ "Other (Grocery/School/Etc.)",
      TRUE ~ "Other"
    )
  )

#Check new categories
inspections_categorized |>
  count(restaurant_category, sort = TRUE)

Violation “Fingerprint” Plot

#Summary table
violation_fingerprint <- inspections_categorized |>
  filter(
    restaurant_category != "Other",
    restaurant_category != "Other (Grocery/School/Etc.)",
    violation_category != "Other"
  ) |>
  count(restaurant_category, violation_category) |>
  group_by(restaurant_category) |>
  mutate(proportion = n / sum(n)) |>
  ungroup()

# Plot the "fingerprint"
ggplot(violation_fingerprint, 
       aes(x = violation_category, y = proportion, fill = violation_category)) +
  geom_col() +
  facet_wrap(~ restaurant_category) + 
  scale_y_continuous(labels = label_percent()) +
  theme(
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    legend.position = "bottom"
  ) +
  labs(
    title = "Violation 'Fingerprint' by Restaurant Category",
    y = "Proportion of All Violations",
    x = "Violation Type",
    fill = "Violation Category"
  )

Restaurant categories do disproportionately receive certain violation types. While “Sanitation & Cleaning” is a universal problem, specific models carry unique risks. The most important takeaway is that Sanitation & Cleaning (pink) and Pest Control (blue) are the two largest violation categories across nearly all restaurant types. However, the proportion of other key categories reveals important differences:

Pest Control Dominance:

Sushi/Japanese, Sandwich/Deli, and Bar/Pubs have the highest proportion of Pest Control violations, consistently making up over 25% of their total issues.

Sanitation & Cleaning Focus:

Coffee/Bakery, Pizza, and Chinese restaurants are highly dominated by Sanitation & Cleaning violations (pink), with this category often exceeding 40% of their total violations.

Food Temperature Risk (The Outlier):

Restaurant (General) is the only category where Food Temperature (teal) makes up the largest non-Sanitation/Pest share, hitting approximately 25–30% of its violations. This suggests that businesses with diverse menus and complex cooking processes are uniquely prone to temperature-related failures.

Cross-Contamination Risk:

Mexican and Sandwich/Deli restaurants show a slightly elevated proportional risk for Cross-Contamination (red), often related to the high volume of raw preparation (e.g., cutting vegetables, preparing salsas, handling deli meats).

Standardize Inspection Types

inspections_categorized <- inspections_categorized |>
  mutate(
    type_lower = tolower(inspection_type),
    
    inspection_type_standard = case_when(
      # Keywords for complaint
      str_detect(type_lower, "complaint|311|owner complaint") ~ "Complaint",
      
      # Keywords for routine
      str_detect(type_lower, "routine|cycle|canvass|regular") ~ "Routine",
      
      # Keywords for follow-ups
      str_detect(type_lower, "re-inspection|reinspection|follow-up") ~ "Follow-Up",
      
      TRUE ~ "Other"
    )
  )

#new standardized categories
inspections_categorized |>
  count(inspection_type_standard, sort = TRUE)

Plot Severity by Inspection Type


inspections_categorized |>
  # 1. Filter the data (No changes needed here)
  filter(
    inspection_type_standard %in% c("Routine", "Complaint"),
    risk_level_standard != "Unknown"
  ) |> # <--- PIPE TO THE NEXT STEP
  
  # 2. Mutate (Convert to Factor)
  mutate(
    risk_level_standard = factor(
      risk_level_standard, 
      # Set the desired hierarchical order
      levels = c("High", "Medium", "Low"),
      ordered = TRUE
    )
  ) |> # <--- CORRECT PIPE PLACEMENT (Outside the final mutate parenthesis)
  
  # 3. Plot proportions
  ggplot(aes(x = inspection_type_standard, fill = risk_level_standard)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_viridis_d(option = "C") +
  labs(
    title = "Violation Severity by Inspection Type",
    x = "Inspection Type",
    y = "Proportion of Violations",
    fill = "Risk Level"
  )

The proportional plot clearly shows that Complaint-Driven inspections are more likely to find severe problems than Routine inspections12. The proportion of High Risk violations is visually larger in the Complaint column than in the Routine column13. This suggests the public is effective at reporting restaurants that pose an immediate public health risk.

Plot Violation Type by Inspection Type

inspections_categorized |>
  filter(
    inspection_type_standard %in% c("Routine", "Complaint"),
    violation_category != "Other" # Remove 'Other' violations
  ) |>
  
  # Plot proportions
  ggplot(aes(x = inspection_type_standard, fill = violation_category)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_viridis_d() +
  labs(
    title = "Violation Types by Inspection Type",
    x = "Inspection Type",
    y = "Proportion of Violations",
    fill = "Violation Category"
  ) +
  coord_flip() # Flip axes to make categories easier to read

When looking at violation type, Complaint inspections are disproportionately focused on Pest Control and Food Temperature issues. In contrast, Routine inspections find a much higher proportion of Sanitation & Cleaning and Facility/Maintenance problems. This suggests that patrons are quick to report visible signs of pests or temperature issues, while inspectors find more structural/hygiene problems during unannounced, comprehensive checks.

Our analysis confirms two critical relationships:

  1. Business Model Risk: The type of cuisine a restaurant serves creates a unique “fingerprint” of health risks (Q1). Complex cooking (Restaurant General) correlates with Food Temperature issues, while high-volume raw preparation (Sushi/Deli) correlates with Pest Control and Cross-Contamination.
  2. Inspection Type Bias: Public complaints (Q2) are highly effective at flagging immediate public health threats, demonstrating a higher proportional incidence of High Risk violations and Pest Control problems compared to routine inspections.
LS0tCnRpdGxlOiAiUiBTdHVkZW50cyBQcm9qZWN0IE5vdGVib29rIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgojIyMgTG9hZCBMaWJyYXJpZXMgYW5kIERhdGEKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkodmlyaWRpcykKCiMgTG9hZCB0aGUgc2luZ2xlLCBmaW5hbCBjbGVhbiBmaWxlCmluc3BlY3Rpb25zIDwtIHJlYWRfY3N2KCJkYXRhL2luc3BlY3Rpb25zX2NsZWFuLmNzdiIpCmBgYAoKIyMgRURBIFJlcG9ydApUaGUgZ29hbCBvZiB0aGlzIHNlY3Rpb24gaXMgdG8gdW5kZXJzdGFuZCB0aGUgb3ZlcmFsbCBzaGFwZSBvZiBvdXIgZGF0YS4KCiMjIyBCYXNpYyBQbG90cwpgYGB7ciBCYXNpYyBQbG90c30KIyBJbnNwZWN0aW9ucyBieSBDaXR5CmdncGxvdChpbnNwZWN0aW9ucywgYWVzKHggPSBjaXR5X3NvdXJjZSkpICsgZ2VvbV9iYXIoKSArIGxhYnModGl0bGUgPSAiSW5zcGVjdGlvbnMgYnkgQ2l0eSIpICsgdGhlbWVfbWluaW1hbCgpCgojT3V0Y29tZXMKZ2dwbG90KGluc3BlY3Rpb25zLCBhZXMoeCA9IGluc3BlY3Rpb25fb3V0Y29tZSkpICsgCiAgZ2VvbV9iYXIoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2NvbW1hKCkpICsKICBsYWJzKHRpdGxlID0gIk91dGNvbWVzIikKCiNSaXNrcwpnZ3Bsb3QoaW5zcGVjdGlvbnMsIGFlcyh4ID0gcmlza19sZXZlbF9zdGFuZGFyZCkpICsgCiAgbGFicyh0aXRsZSA9ICJSaXNrcyIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2NvbW1hKCkpICsgCiAgZ2VvbV9iYXIoKQogIAojVGltZSBSYW5nZSBvZiB0aGUgRGF0YQpnZ3Bsb3QoaW5zcGVjdGlvbnMsIGFlcyh4ID0gaW5zcGVjdGlvbl9kYXRlKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsgCnNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9jb21tYSgpKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgSW5zcGVjdGlvbnMgT3ZlciBUaW1lIiwgeCA9ICJEYXRlIiwgeSA9ICJDb3VudCIpCmBgYApPdXIgaW5pdGlhbCBwaGFzZSBvZiBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIChFREEpIGZvY3VzZWQgb24gdW5kZXJzdGFuZGluZyB0aGUgb3ZlcmFsbCBzaGFwZSwgZGlzdHJpYnV0aW9uLCBhbmQgaW50ZWdyaXR5IG9mIG91ciBjb21iaW5lZCAxLjQgbWlsbGlvbi1yb3cgZGF0YXNldC4gVGhpcyBpbml0aWFsIGFuYWx5c2lzIGNvbmZpcm1zIG91ciBjb21iaW5lZCBkYXRhc2V0IGlzIGxhcmdlLCB1c2FibGUsIGFuZCBtb2Rlcm4sIGJ1dCBjcml0aWNhbGx5IGltYmFsYW5jZWQuCgpQbG90IDE6IEluc3BlY3Rpb25zIGJ5IENpdHkKVGhpcyBiYXIgY2hhcnQgc2hvd3MgdGhlIHRvdGFsIG51bWJlciBvZiBpbnNwZWN0aW9ucyBjb250cmlidXRlZCBieSBlYWNoIGNpdHkuIFRoZSBrZXkgZmluZGluZyBoZXJlIGlzIHRoYXQgb3VyIGRhdGFzZXQgaXMgaGVhdmlseSBpbWJhbGFuY2VkLiBCb3N0b24gaXMgdGhlIHNvdXJjZSBvZiBhIGxhcmdlIG1ham9yaXR5IG9mIG91ciBkYXRhIChvdmVyIDc1MCwwMDAgcm93cyksIHdoaWxlIENoaWNhZ28gYW5kIE5ldyBZb3JrIGFyZSBzaW1pbGFybHkgc2l6ZWQsIGFuZCBTYW4gRnJhbmNpc2NvIGlzIG91ciBzbWFsbGVzdCBkYXRhc2V0LgoKVGhpcyBpcyBhIGNyaXRpY2FsIGZpbmRpbmcgYmVjYXVzZSBpdCBjb25maXJtcyB0aGF0IHdlIGNhbm5vdCB1c2UgcmF3IGNvdW50cyB0byBjb21wYXJlIGNpdGllcy4gQWxsIGZ1dHVyZSBjaXR5LXRvLWNpdHkgY29tcGFyaXNvbnMgbXVzdCBiZSBiYXNlZCBvbiBwcm9wb3J0aW9ucyBvciBwZXJjZW50YWdlcyAodXNpbmcgcG9zaXRpb24gPSAiZmlsbCIpIHRvIGJlIGZhaXIgYW5kIGFjY3VyYXRlLgoKUGxvdCAyOiBPdmVyYWxsIEluc3BlY3Rpb24gT3V0Y29tZXMKVGhpcyBwbG90IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2Ygb3VyIG5ld2x5LWNyZWF0ZWQgaW5zcGVjdGlvbl9vdXRjb21lIGNvbHVtbiBhY3Jvc3MgdGhlIGVudGlyZSBkYXRhc2V0LiBXaGlsZSAiRmFpbCIgYW5kICJQYXNzIiBhcmUgdGhlIG1vc3QgZnJlcXVlbnQgb3V0Y29tZXMsIHRoaXMgcGxvdCBpcyBoZWF2aWx5IHNrZXdlZCBieSB0aGUgZGlzcHJvcG9ydGlvbmF0ZSBzaXplIG9mIHRoZSBCb3N0b24gZGF0YS4gV2UgY2FuJ3QgZHJhdyBhbnkgcmVhbCBjb25jbHVzaW9ucyBmcm9tIHRoaXMgeWV0LiBJdHMgbWFpbiBwdXJwb3NlIGZvciBub3cgaXMgdG8gY29uZmlybSB0aGF0IG91ciBjYXNlX3doZW4oKSBsb2dpYyBzdWNjZXNzZnVsbHkgY2F0ZWdvcml6ZWQgYWxsIDEuNCBtaWxsaW9uIHJvd3MuCgpQbG90IDM6IERpc3RyaWJ1dGlvbiBvZiBJbnNwZWN0aW9ucyBPdmVyIFRpbWUKVGhpcyBoaXN0b2dyYW0gaXMgb25lIG9mIG91ciBtb3N0IGltcG9ydGFudCBpbml0aWFsIHBsb3RzLiBJdCBjb25maXJtcyB0d28gdGhpbmdzOgoKVGhlIGRhdGEgaXMgcmVjZW50OiBUaGUgdmFzdCBtYWpvcml0eSBvZiBvdXIgaW5zcGVjdGlvbnMgb2NjdXJyZWQgZnJvbSByb3VnaGx5IDIwMDUgdG8gdGhlIHByZXNlbnQsIHdoaWNoIGlzIGV4Y2VsbGVudCBmb3IgYW5zd2VyaW5nIG91ciByZXNlYXJjaCBxdWVzdGlvbnMgYWJvdXQgbW9kZXJuIHRyZW5kcy4KCldlIGhhdmUgImJhZCBkYXRhIiB0byBmaWx0ZXI6IFRoZSBwbG90IGNsZWFybHkgaWRlbnRpZmllcyBhIHNtYWxsIGNsdXN0ZXIgb2YgImJhZCBkYXRhIiAocGxhY2Vob2xkZXIgZGF0ZXMgZnJvbSAxOTAwKSB0aGF0IHdlIG11c3QgZmlsdGVyIG91dCBiZWZvcmUgY29uZHVjdGluZyBhbnkgdGltZS1zZXJpZXMgYW5hbHlzaXMuIFRoZSB3YXJuaW5nIG1lc3NhZ2UgYWxzbyBjb25maXJtZWQgdGhhdCBhIG5lZ2xpZ2libGUgbnVtYmVyIG9mIHJvd3MgKH42LDQwMCwgb3IgPDAuNSUpIHdlcmUgZHJvcHBlZCBkdWUgdG8gbWlzc2luZyBkYXRlcywgd2hpY2ggd2lsbCBub3QgaW1wYWN0IG91ciBhbmFseXNpcy4KCgojIyMgQ2l0eSBDb21wYXJpc29ucwpgYGB7ciBDaXR5IENvbXBhcmlzb25zfQojT3V0Y29tZXMgYnkgQ2l0eQpnZ3Bsb3QoaW5zcGVjdGlvbnMsIGFlcyh4ID0gY2l0eV9zb3VyY2UsIGZpbGwgPSBpbnNwZWN0aW9uX291dGNvbWUpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArIAogIGxhYnModGl0bGUgPSAiT3V0Y29tZXMgYnkgQ2l0eSIsIHkgPSAiUHJvcG9ydGlvbiIpCgojUmlzayBMZXZlbCBieSBDaXR5CmdncGxvdChpbnNwZWN0aW9ucywgYWVzKHggPSBjaXR5X3NvdXJjZSwgZmlsbCA9IHJpc2tfbGV2ZWxfc3RhbmRhcmQpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArCiAgICBsYWJzKHRpdGxlID0gIlJpc2sgTGV2ZWwgYnkgQ2l0eSIsIHkgPSAiUHJvcG9ydGlvbiIpCgojU2NvcmUgRGlzdHJpYnV0aW9ucwpnZ3Bsb3QoaW5zcGVjdGlvbnMsIGFlcyh4ID0gY2l0eV9zb3VyY2UsIHkgPSBpbnNwZWN0aW9uX3Njb3JlKSkgKyAKICBnZW9tX2JveHBsb3QoKSArCiAgICBsYWJzKHRpdGxlID0gIlNjb3JlIERpc3RyaWJ1dGlvbnMiKQoKZ2dwbG90KGluc3BlY3Rpb25zLCBhZXMoeCA9IGluc3BlY3Rpb25fb3V0Y29tZSwgeSA9IGluc3BlY3Rpb25fc2NvcmUsIGZpbGwgPSBjaXR5X3NvdXJjZSkpICsKICBnZW9tX2JveHBsb3QoKSArIAogIGZhY2V0X3dyYXAofiBjaXR5X3NvdXJjZSkgKyAjc2hvdyBob3cgb3VyIHN0YW5kYXJkaXplZCBQYXNzL0ZhaWwgY2F0ZWdvcmllcyBsaW5lIHVwIHdpdGggdGhlIG51bWVyaWMgc2NvcmVzCiAgICBsYWJzKHRpdGxlID0gIlNjb3JlIERpc3RyaWJ1dGlvbnMgYnkgQ2l0eSAoU3RhbmRhcmRpemVkIikKCmBgYApBZnRlciBlc3RhYmxpc2hpbmcgdGhlIG92ZXJhbGwgc2hhcGUgb2Ygb3VyIGRhdGEsIHdlIGRyaWxsZWQgZG93biB0byBjb21wYXJlIHRoZSBmb3VyIGNpdGllcy4gVGhpcyBpcyB3aGVyZSBvdXIgc3RhbmRhcmRpemF0aW9uIGVmZm9ydHMgcHJvdmlkZSB0aGVpciBmaXJzdCBtYWpvciBpbnNpZ2h0cywgcmV2ZWFsaW5nIHRoYXQgdGhlIGNpdGllcyBoYXZlIHZhc3RseSBkaWZmZXJlbnQgaW5zcGVjdGlvbiBwcm9maWxlcy4KClBsb3QgNDogUHJvcG9ydGlvbnMgb2YgT3V0Y29tZXMgYnkgQ2l0eSAKVGhpcyBwbG90IGRpcmVjdGx5IGNvbXBhcmVzIHRoZSBwYXNzL2ZhaWwgcmF0ZXMgZm9yIGVhY2ggY2l0eS4gV2UgZm91bmQgdGhhdCBCb3N0b24gYW5kIFNhbiBGcmFuY2lzY28gaGF2ZSB0aGUgaGlnaGVzdCBwcm9wb3J0aW9uIG9mICJGYWlsIiBvdXRjb21lcy4gSW4gY29udHJhc3QsIE5ldyBZb3JrJ3MgcHJvZmlsZSBpcyBkb21pbmF0ZWQgYnkgIlBhc3MiIChyZWZsZWN0aW5nIHRoZWlyICdBJyBncmFkZXMpIGFuZCAiUGVuZGluZyIgcmVzdWx0cy4gVGhpcyBjb25maXJtcyB0aGF0IGVhY2ggY2l0eSdzIGdyYWRpbmcgc3lzdGVtIGlzIHVuaXF1ZSBhbmQgdGhhdCBvdXIgaW5zcGVjdGlvbl9vdXRjb21lIGNvbHVtbiBzdWNjZXNzZnVsbHkgY2FwdHVyZWQgdGhlc2UgZGlmZmVyZW5jZXMuCgpQbG90IDU6IFByb3BvcnRpb24gb2YgUmlzayBMZXZlbCBieSBDaXR5ClRoaXMgaXMgb25lIG9mIHRoZSBtb3N0IHN0cmlraW5nIGZpbmRpbmdzIHNvIGZhci4gQ2hpY2FnbyBhbmQgTmV3IFlvcmsgbG9nIGEgZHJhbWF0aWNhbGx5IGhpZ2hlciBwcm9wb3J0aW9uIG9mICJIaWdoIFJpc2siIHZpb2xhdGlvbnMgdGhhbiBCb3N0b24gYW5kIFNhbiBGcmFuY2lzY28uIEluIENoaWNhZ28sICJIaWdoIFJpc2siIGFwcGVhcnMgdG8gYmUgdGhlIG1vc3QgY29tbW9uIGNhdGVnb3J5LCB3aGlsZSBpbiBCb3N0b24sICJMb3cgUmlzayIgaXMgZG9taW5hbnQuIFRoaXMgbWF5IHJlZmxlY3QgZGlmZmVyZW50IHB1YmxpYyBoZWFsdGggZGVmaW5pdGlvbnMgb2YgInJpc2siIG9yIGRpZmZlcmVudCBhcmVhcyBvZiBmb2N1cyBmb3IgZWFjaCBjaXR5J3MgaW5zcGVjdG9ycy4KClBsb3QgNiAmIDc6IFNjb3JlIERpc3RyaWJ1dGlvbnMKVGhlc2UgdHdvIHBsb3RzICh3aGljaCB3ZSd2ZSBjb21iaW5lZCBmb3IgYW5hbHlzaXMpIGNvbmZpcm0gb3VyIGluc3BlY3Rpb25fb3V0Y29tZSBsb2dpYyBhbmQgcmV2ZWFsIHRoZSBpbnZlcnRlZCBuYXR1cmUgb2YgdGhlIHNjb3Jpbmcgc3lzdGVtcy4KCk5ZQyB1c2VzIGEgZGVtZXJpdCBzeXN0ZW06IEEgbG93ZXIgc2NvcmUgaXMgYmV0dGVyLiBPdXIgcGxvdCBzaG93cyB0aGF0ICJQYXNzIiAoR3JhZGUgQSkgaGFzIHRoZSBsb3dlc3Qgc2NvcmVzLCB3aGlsZSAiRmFpbCIgKEdyYWRlIEMpIGhhcyB0aGUgaGlnaGVzdC4KClNGIHVzZXMgYSBwb2ludHMtYmFzZWQgc3lzdGVtOiBBIGhpZ2hlciBzY29yZSBpcyBiZXR0ZXIuIE91ciBwbG90IGNvbmZpcm1zIHRoaXMsIHNob3dpbmcgIlBhc3MiICg5MCspIGhhcyB0aGUgaGlnaGVzdCBzY29yZXMgYW5kICJGYWlsIiAoNzEtODUpIGhhcyBsb3dlciBzY29yZXMuCgpUaGlzIGFuYWx5c2lzIHZhbGlkYXRlcyBvdXIgc3RhbmRhcmRpemF0aW9uIGFuZCBwcm92ZXMgdGhhdCB0aGUgdHdvIHNjb3Jpbmcgc3lzdGVtcyBhcmUgZGlyZWN0IG9wcG9zaXRlcy4KCiMjIyBFeHBsb3JpbmcgRmFpbCBSYXRlcyBPdmVyIFRpbWUgCmBgYHtyIEV4cGxvcmluZyBGYWlsIFJhdGVzfQoKIyBDcmVhdGUgYSBzdW1tYXJ5IHRhYmxlCmZhaWxzX2J5X3llYXIgPC0gaW5zcGVjdGlvbnMgfD4KICBmaWx0ZXIoaW5zcGVjdGlvbl9kYXRlID4gIjIwMDAtMDEtMDEiKSB8PiAjIGZpbHRlciBvdXQgJ2JhZCcgZGF0ZXMKICBtdXRhdGUoeWVhciA9IHllYXIoaW5zcGVjdGlvbl9kYXRlKSkgfD4KICBncm91cF9ieShjaXR5X3NvdXJjZSwgeWVhcikgfD4KICBzdW1tYXJpemUoCiAgICBmYWlsX3JhdGUgPSBtZWFuKGluc3BlY3Rpb25fb3V0Y29tZSA9PSAiRmFpbCIsIG5hLnJtID0gVFJVRSksCiAgICB0b3RhbF9pbnNwZWN0aW9ucyA9IG4oKQogICkgfD4KICBmaWx0ZXIodG90YWxfaW5zcGVjdGlvbnMgPiAxMDApICMgUmVtb3ZlIHllYXJzIHdpdGggdGlueSBkYXRhCgojIFBsb3QgdGhlIHN1bW1hcnkKZ2dwbG90KGZhaWxzX2J5X3llYXIsIGFlcyh4ID0geWVhciwgeSA9IGZhaWxfcmF0ZSwgY29sb3IgPSBjaXR5X3NvdXJjZSkpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfcGVyY2VudCgpKSArICAgICAjIGZvcm1hdCB5LWF4aXMgYXMgcGVyY2VudGFnZQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgIyBhZGQgYmV0dGVyIGNvbG9ycwogIGxhYnMoCiAgICB0aXRsZSA9ICJGYWlsIFJhdGUgT3ZlciBUaW1lIGJ5IENpdHkiLCAKICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBGYWlscyIsICAgICAgICAgICAgICAgICAgICAgICMgPC0tIEZpeCB5LWF4aXMgbGFiZWwKICAgIHggPSAiWWVhciIsCiAgICBjb2xvciA9ICJDaXR5IiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIDwtLSBGaXggbGVnZW5kIHRpdGxlCiAgKQoKIyBMZWFzdCBTdWNjZXNzZnVsIHppcGNvZGVzIGluIGVhY2ggY2l0eSBpbiB0aGUgZGF0YXNldApmYWlsc19ieV96aXAgPC0gaW5zcGVjdGlvbnMgfD4KICBmaWx0ZXIoaW5zcGVjdGlvbl9kYXRlID4gIjIwMDAtMDEtMDEiKSB8PiAjIEdvb2QgaWRlYSB0byBmaWx0ZXIgYmFkIGRhdGVzCiAgZ3JvdXBfYnkoY2l0eV9zb3VyY2UsIHppcF9jb2RlKSB8PgogIHN1bW1hcml6ZSgKICAgIGZhaWxfcmF0ZSA9IG1lYW4oaW5zcGVjdGlvbl9vdXRjb21lID09ICJGYWlsIiwgbmEucm0gPSBUUlVFKSwKICAgIHRvdGFsX2luc3BlY3Rpb25zID0gbigpCiAgKSB8PgogIGZpbHRlcih0b3RhbF9pbnNwZWN0aW9ucyA+IDEwMCkgfD4gIyBPbmx5IGluY2x1ZGUgemlwcyB3aXRoIDEwMCsgaW5zcGVjdGlvbnMKICB1bmdyb3VwKCkKCiMgU3VtbWFyeSB0YWJsZSBmb3IgemlwIGNvZGVzCmZhaWxzX2J5X3ppcCB8PgogIGdyb3VwX2J5KGNpdHlfc291cmNlKSB8PiAgICAgICMgR3JvdXAgYnkgY2l0eQogIHRvcF9uKDMsIGZhaWxfcmF0ZSkgfD4gICAgICAgICMgRmluZCB0aGUgdG9wIDMgKndpdGhpbiogdGhhdCBjaXR5CiAgdW5ncm91cCgpIHw+CiAgCiAgIyBUaGlzICdyZW9yZGVyX3dpdGhpbicgaXMgYSBzcGVjaWFsIHRyaWNrIHRvIG1ha2UgZmFjZXRzIHdvcmsKICBtdXRhdGUoCiAgICB6aXBfY29kZSA9IHRpZHl0ZXh0OjpyZW9yZGVyX3dpdGhpbih6aXBfY29kZSwgZmFpbF9yYXRlLCBjaXR5X3NvdXJjZSkKICApIHw+CgogIGdncGxvdChhZXMoeCA9IHppcF9jb2RlLCB5ID0gZmFpbF9yYXRlLCBmaWxsID0gY2l0eV9zb3VyY2UpKSArCiAgZ2VvbV9jb2woKSArCiAgdGlkeXRleHQ6OnNjYWxlX3hfcmVvcmRlcmVkKCkgKyAjIFRoaXMgbWFrZXMgdGhlIGxhYmVscyBwbG90IGNvcnJlY3RseQogIGZhY2V0X3dyYXAofiBjaXR5X3NvdXJjZSwgc2NhbGVzID0gImZyZWUiKSArICNDcmVhdGUgNCBzZXBhcmF0ZSBjaGFydHMKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUb3AgMyBaaXAgQ29kZXMgd2l0aCBIaWdoZXN0IEZhaWwgUmF0ZSBieSBDaXR5IiwKICAgIHggPSAiWmlwIENvZGUiLAogICAgeSA9ICJGYWlsIFJhdGUiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKYGBgCgpGb2xsb3dpbmcgb3VyIGNpdHktbGV2ZWwgY29tcGFyaXNvbnMsIHdlIG1vdmVkIGludG8gb3VyIGZpcnN0IG11bHRpdmFyaWF0ZSBhbmFseXNpcyB0byBhbnN3ZXIgb3VyIHJlc2VhcmNoIHF1ZXN0aW9ucyBhYm91dCB3aGVyZSBhbmQgd2hlbiB2aW9sYXRpb25zIG9jY3VyLgoKUGxvdCA4OiBGYWlsIFJhdGUgT3ZlciBUaW1lIGJ5IENpdHkKVGhpcyBsaW5lIGdyYXBoIHBsb3RzIHRoZSBwcm9wb3J0aW9uIChwZXJjZW50YWdlKSBvZiAiRmFpbCIgb3V0Y29tZXMgZm9yIGVhY2ggY2l0eSwgZnJvbSAyMDA4IHRvIDIwMjUuIFRoaXMgaXMgb3VyIG1vc3Qgc2lnbmlmaWNhbnQgZmluZGluZyBzbyBmYXI6CgpEcmFtYXRpY2FsbHkgRGlmZmVyZW50IFN5c3RlbXM6IFRoZSBkZWZpbml0aW9uIG9mIGEgIkZhaWwiIGlzIGNsZWFybHkgbm90IHN0YW5kYXJkaXplZC4KCkJvc3RvbjogSGFzIGEgdmVyeSBoaWdoIGFuZCBjb25zaXN0ZW50ICJGYWlsIiByYXRlLCBob3ZlcmluZyBhcm91bmQgNjAlIGZvciB0aGUgZW50aXJlIDE1LXllYXIgcGVyaW9kLiBUaGlzIHN0cm9uZ2x5IHN1Z2dlc3RzIHRoYXQgQm9zdG9uJ3MgcmVzdWx0IGNvbHVtbiBsb2dzIGEgIkZhaWwiIGZvciBldmVuIG1pbm9yIGluZnJhY3Rpb25zLCBtYWtpbmcgaXQgYSB2ZXJ5IGNvbW1vbiBvdXRjb21lLgoKQ2hpY2FnbzogU2hvd3MgYSBwb3NpdGl2ZSB0cmVuZC4gSXRzIGZhaWwgcmF0ZSBoYXMgc3RlYWRpbHkgZGVjcmVhc2VkIGZyb20gfjI1JSBpbiAyMDEwIHRvIGEgc3RhYmxlIH4xOC0yMCUgaW4gcmVjZW50IHllYXJzLgoKTmV3IFlvcms6IEhhcyBhbiBleHRyZW1lbHkgbG93IGZhaWwgcmF0ZSwgY29uc2lzdGVudGx5IHN0YXlpbmcgYmVsb3cgMTAlLiBUaGlzIGFsaWducyBwZXJmZWN0bHkgd2l0aCB0aGVpciAiR3JhZGUgQSIgc3lzdGVtLCB3aGVyZSBhICdDJyAod2hpY2ggd2UgbWFwcGVkIHRvICJGYWlsIikgaXMgcmFyZS4KClNhbiBGcmFuY2lzY286IEFwcGVhcnMgdG8gaGF2ZSBhIGZhaWwgcmF0ZSBvZiBhcm91bmQgMzAlLCBsYW5kaW5nIGJldHdlZW4gQm9zdG9uIGFuZCB0aGUgb3RoZXIgdHdvIGNpdGllcy4KClBsb3QgOTogVG9wIDMgV29yc3QgWmlwIENvZGVzIGJ5IENpdHkKVGhpcyBiYXIgY2hhcnQgd2FzIGludGVuZGVkIHRvIGZpbmQgdGhlICJ3b3JzdCIgemlwIGNvZGVzIGFjcm9zcyB0aGUgZW50aXJlIGRhdGFzZXQuCldlIGhhdmUgbm93IHN1Y2Nlc3NmdWxseSBpZGVudGlmaWVkIHNwZWNpZmljIGdlb2dyYXBoaWMgYXJlYXMgb2YgY29uY2VybiBmb3IgZWFjaCBjaXR5OgoKQm9zdG9uOiAwMjExOS0zMjEyLCAwMjEyMAoKQ2hpY2FnbzogNjA4MjcsIDYwNjE5CgpOZXcgWW9yazogMTE0MzYsIDExNDI4CgpTYW4gRnJhbmNpc2NvOiA5NDEzNCwgOTQxMTgKCiMjIyBCb3N0b24gWmlwY29kZXMgTWFwCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpib3NfaW5zcCA8LSBpbnNwZWN0aW9ucyB8PgogIGZpbHRlcihjaXR5X3NvdXJjZSA9PSAiQm9zdG9uIikKYm9zX3NocCA8LSBzdF9yZWFkKCJCb3N0b24gU2hhcGVmaWxlcy9aSVBfQ29kZXMuc2hwIikKCmJvc19ib3JkZXJzIDwtIGJvc19zaHAgfD4gc3RfdW5pb24oKSB8PgogIHN0X2J1ZmZlciguNSkKZ2dwbG90KGJvc19ib3JkZXJzKSArCiAgZ2VvbV9zZihkYXRhPWJvcywgYWVzKGZpbGwgPSBaSVA1KSkKCgojIERlbnNpdHkgbWFwIG9mIHJlc3RhdXJhbnRzIGluIGVhY2ggemlwY29kZQoKcnN0bnRfZGVuc2l0eSA8LSBib3NfaW5zcCB8PgogIGdyb3VwX2J5KHJlc3RhdXJhbnRfbmFtZSkgfD4KICBncm91cF9ieSh6aXBfY29kZSkgfD4KICBtdXRhdGUobl9wZXJfemlwID0gTigpKQoKYm9zJHppcF9jb2RlIDwtIGJvcyRaSVA1Cgpib3MgPC0gZnVsbF9qb2luKHJzdG50X2RlbnNpdHksIGJvcywgYnkgPSB6aXBfY29kZSkKCmdncGxvdChib3NfYm9yZGVycykgKwogIGdlb21fc2YoZGF0YT1ib3MsIGFlcyhmaWxsX25fcGVyX3ppcCkpCmBgYAoKVGhlcmUgYXJlIDQzIHppcCBjb2RlcyBpbiB0aGUgQ2l0eSBvZiBCb3N0b24KCiMjIyBUb3AgVmlvbGF0aW9ucyBPdmVyYWxsCgpgYGB7ciBUb3AgVmlvbGF0aW9ucyBPdmVyYWxsfQp0b3BfYmlncmFtcyA8LSBpbnNwZWN0aW9ucyB8PgogIHNhbXBsZV9mcmFjKDAuNSkgfD4gICMgVGFraW5nIGEgNTAlIHJhbmRvbSBzYW1wbGUgdG8gcmVkdWNlIG1lbW9yeSBsb2FkCiAgZmlsdGVyKCFpcy5uYSh2aW9sYXRpb25fZGVzYykpIHw+CiAgdW5uZXN0X3Rva2VucyhiaWdyYW0sIHZpb2xhdGlvbl9kZXNjLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgfD4KICBjb3VudChiaWdyYW0sIHNvcnQgPSBUUlVFKQoKIyBQbG90IHRoZSB0b3AgMjAKdG9wX2JpZ3JhbXMgfD4KICB0b3BfbigyMCkgfD4KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGJpZ3JhbSwgbiksIHkgPSBuKSkgKwogIGdlb21fY29sKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHRpdGxlID0gIlRvcCAyMCBNb3N0IENvbW1vbiBWaW9sYXRpb24gUGhyYXNlcyAoNTAlIFNhbXBsZSkiLAogICAgeCA9ICJWaW9sYXRpb24gUGhyYXNlIChCaWdyYW0pIiwKICAgIHkgPSAiVG90YWwgQ291bnQiCiAgKQpgYGAKClRoaXMgcGxvdCwgZGVzcGl0ZSBzdWNjZXNzZnVsbHkgcHJvY2Vzc2luZyB0aGUgdGV4dCwgc2hvd3MgdGhhdCB0aGUgbW9zdCBjb21tb24gcGhyYXNlcyBhY3Jvc3MgYWxsIGNpdGllcyBhcmUgZ2VuZXJpYywgaGlnaC1mcmVxdWVuY3kgZnVuY3Rpb25hbCB3b3JkcyBsaWtlICdmb29kIGNvbnRhY3QnIGFuZCAnbm9uIGZvb2QnLiBXZSBkbyBub3Qgc2VlIHNwZWNpZmljIGlzc3VlcyBsaWtlICdyb2RlbnQnIG9yICdpbXByb3BlciB0ZW1wZXJhdHVyZScgaW4gdGhlIHRvcCAyMCwgY29uZmlybWluZyB0aGF0IHRoZXNlIGtleSBpc3N1ZXMgYXJlIGRpbHV0ZWQgYnkgY29tbW9uLCBnZW5lcmFsIHBocmFzZXMuIFRoaXMgdmFsaWRhdGVzIG91ciBuZXh0IHN0ZXAgdG8gdXNlIG1hbnVhbCBrZXl3b3JkIHNlYXJjaGluZyB0byBncm91cCB0aG91c2FuZHMgb2YgdW5pcXVlIHZpb2xhdGlvbnMgaW50byBtZWFuaW5nZnVsIGNhdGVnb3JpZXMuCgojIyMgRGF5cyBvZiB0aGUgd2VlayB0aGF0IHNlZSB0aGUgbW9zdCBpbnNwZWN0aW9ucwoKYGBge3IgSW5zcGVjdGlvbnMgYnkgRGF5IG9mIFdlZWt9Cmluc3BlY3Rpb25zIHw+IAogIG11dGF0ZSh3ZGF5ID0gd2RheShpbnNwZWN0aW9uX2RhdGUsIGxhYmVsID0gVFJVRSkpIHw+IAogIGNvdW50KHdkYXkpIHw+CiAgZ2dwbG90KGFlcyh3ZGF5LCBuKSkgKwogIGdlb21fY29sKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9jb21tYSgpKSArCiAgbGFicyh0aXRsZSA9ICJJbnNwZWN0aW9ucyBieSBEYXkgb2YgV2VlayIpCmBgYAoKVGhpcyBhbmFseXNpcyBjb25maXJtcyB0aGF0IGluc3BlY3Rpb24gZnJlcXVlbmN5IGlzIGhlYXZpbHkgc2tld2VkIHRvd2FyZCB3ZWVrZGF5cywgd2l0aCBhIHNsaWdodCBwZWFrIG9uIFR1ZXNkYXkuIFRoZSBsb3cgY291bnRzIG9uIFN1bmRheSBhbmQgU2F0dXJkYXkgIHN1Z2dlc3QgdGhhdCB3ZWVrZW5kIGluc3BlY3Rpb25zIGFyZSByYXJlIG9yIHJlc2VydmVkIG9ubHkgZm9yIHNwZWNpZmljIGZhY2lsaXRpZXMuCgojIyMgSW5zcGVjdGlvbiBGcmVxdWVuY3kgcGVyIFJlc3RhdXJhbnQKCmBgYHtyIEluc3BlY3Rpb25zIHBlciBSZXN0YXVyYW50fQpnZ3Bsb3QoaW5zcGVjdGlvbnMgfD4gY291bnQocmVzdGF1cmFudF9uYW1lKSwgYWVzKG4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYnJlYWtzID0gc2VxKDAsIDUwLCBieSA9IDEpLCBjb2xvcj0iYmxhY2siLCBmaWxsPSJza3libHVlIikgKwogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBJbnNwZWN0aW9ucyBwZXIgUmVzdGF1cmFudCIsIHg9Ik51bWJlciBvZiBJbnNwZWN0aW9ucyIsIHk9Ik51bWJlciBvZiBSZXN0YXVyYW50cyIpCmBgYAoKVGhlIHRhbGxlc3QgYmFyIHNob3dzIHRoYXQgbmVhcmx5IDEwLDAwMCByZXN0YXVyYW50cyBoYXZlIGJlZW4gaW5zcGVjdGVkIG9ubHkgb25jZSAob3IgY2xvc2UgdG8gb25jZSkgZHVyaW5nIHRoZSBkYXRhc2V0J3MgdGltZSBmcmFtZS4gVGhlIG51bWJlciBvZiByZXN0YXVyYW50cyBkcm9wcyBvZmYgc3RlZXBseSBmb3IgYnVzaW5lc3NlcyBpbnNwZWN0ZWQganVzdCAyLCAzLCBvciA0IHRpbWVzLgpUaGUgbG9uZywgZmxhdCB0YWlsIG9uIHRoZSByaWdodCBpcyBoaWdobHkgc2lnbmlmaWNhbnQuIFdoaWxlIG1vc3QgYnVzaW5lc3NlcyBhcmUgaW5zcGVjdGVkIGluZnJlcXVlbnRseSwgYSBzbWFsbCBidXQgY29uc2lzdGVudCBudW1iZXIgb2YgcmVzdGF1cmFudHMgYXJlIGluc3BlY3RlZCAyMCwgMzAsIDQwLCBvciBldmVuIDUwKyB0aW1lcy4gVGhpcyBtYXkgYmUgZHVlIHRvIHJvdXRpbmUgaW5zcGVjdGlvbnMgaGFwcGVuaW5nLCBidXQgdGhpcyBpcyB1bmxpa2VseSBmb3IgdGhlIHRpbWUgcGVyaW9kIGNvdmVyZWQgaW4gb3VyIGRhdGEuIFRoaXMgY291ZGwgYWxzbyBzdWdnZXN0IHRoYXQgdGhlIGluc3BlY3Rpb24gc3lzdGVtIGlzIGVmZmVjdGl2ZWx5IHVzaW5nIGEgcmlzay1iYXNlZCBhcHByb2FjaC4gUmVzdGF1cmFudHMgdGhhdCBmYWlsIG9yIGhhdmUgc2VyaW91cyB2aW9sYXRpb25zIGFyZSBsaWtlbHkgcHVzaGVkIGludG8gcmUtaW5zcGVjdGlvbiBjeWNsZXMgb3IgcmVjZWl2ZSBtb3JlIGZyZXF1ZW50IHJvdXRpbmUgaW5zcGVjdGlvbnMuIENvbnZlcnNlbHksIHN1Y2Nlc3NmdWwgcmVzdGF1cmFudHMgYXJlIGluc3BlY3RlZCBsZXNzIG9mdGVuLCBmcmVlaW5nIHVwIHJlc291cmNlcy4KCiMjIEFuc3dlcmluZyBSZXNlYXJjaCBRdWVzdGlvbnMKCiMjIFNldW4ncyBBbmFseXNpcyAKIyMjIENhdGVnb3JpemUgVmlvbGF0aW9ucwpgYGB7ciBDYXRlZ29yaXplIFZpb2xhdGlvbnN9Cmluc3BlY3Rpb25zX2NhdGVnb3JpemVkIDwtIGluc3BlY3Rpb25zIHw+CiAgbXV0YXRlKAogICAgdmlvbGF0aW9uX2NhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KHZpb2xhdGlvbl9kZXNjLCAibWljZXxyb2RlbnR8ZHJvcHBpbmdzfGluc2VjdHN8cGVzdHN8aGFyYm9yYWdlIikgfiAiUGVzdCBDb250cm9sIiwKICAgICAgc3RyX2RldGVjdCh2aW9sYXRpb25fZGVzYywgInRlbXBlcmF0dXJlfGNvb2x8aG90LWhvbGRpbmd8Y29sZC1ob2xkaW5nfHJlZnJpZ2VyYXQiKSB+ICJGb29kIFRlbXBlcmF0dXJlIiwKICAgICAgc3RyX2RldGVjdCh2aW9sYXRpb25fZGVzYywgIndhc2h8c2FuaXRpenxjbGVhbnx3aXBpbmcgY2xvdGhzfGRpc2h3YXNoaW5nIikgfiAiU2FuaXRhdGlvbiAmIENsZWFuaW5nIiwKICAgICAgc3RyX2RldGVjdCh2aW9sYXRpb25fZGVzYywgImhhbmQgd2FzaHxoeWdpZW5lfG5vIGhhaXJ8YmFyZSBoYW5kIikgfiAiRW1wbG95ZWUgSHlnaWVuZSIsCiAgICAgIHN0cl9kZXRlY3QodmlvbGF0aW9uX2Rlc2MsICJjb250YW1pbmF0fGNyb3NzLWNvbnRhbWluYXRpb258cmF3fGNvdmVyZWR8cHJvdGVjdCIpIH4gIkNyb3NzLUNvbnRhbWluYXRpb24iLAogICAgICBzdHJfZGV0ZWN0KHZpb2xhdGlvbl9kZXNjLCAiZmxvb3J8d2FsbHxjZWlsaW5nfHBsdW1iaW5nfHZlbnRpbGF0aW9ufGdhcmJhZ2UiKSB+ICJGYWNpbGl0eS9NYWludGVuYW5jZSIsCiAgICAgIFRSVUUgfiAiT3RoZXIiCiAgICApCiAgKQoKI0NoZWNrIG5ldyBjYXRlZ29yaWVzCmluc3BlY3Rpb25zX2NhdGVnb3JpemVkIHw+CiAgY291bnQodmlvbGF0aW9uX2NhdGVnb3J5LCBzb3J0ID0gVFJVRSkKYGBgCgoKIyMjIENhdGVnb3JpemUgUmVzdGF1cmFudHMKYGBge3IgQ2F0ZWdvcml6ZSBSZXN0YXVyYW50c30KaW5zcGVjdGlvbnNfY2F0ZWdvcml6ZWQgPC0gaW5zcGVjdGlvbnNfY2F0ZWdvcml6ZWQgfD4KICBtdXRhdGUoCiAgICAjIENyZWF0ZSBvbmUgY29tYmluZWQgZGVzY3JpcHRpb24gY29sdW1uIHRvIHNlYXJjaAogICAgZGVzY19hbGwgPSBjb2FsZXNjZShjdWlzaW5lX2Rlc2NyaXB0aW9uLCBmYWNpbGl0eV90eXBlLCBkZXNjcmlwdCkgfD4gdG9sb3dlcigpLAogICAgCiAgICByZXN0YXVyYW50X2NhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KGRlc2NfYWxsLCAicGl6emF8cGl6emVyaWEiKSB+ICJQaXp6YSIsCiAgICAgIHN0cl9kZXRlY3QoZGVzY19hbGwsICJzdXNoaXxqYXBhbmVzZSIpIH4gIlN1c2hpL0phcGFuZXNlIiwKICAgICAgc3RyX2RldGVjdChkZXNjX2FsbCwgImNvZmZlZXxjYWZlfGJha2VyeXxkb251dCIpIH4gIkNvZmZlZS9CYWtlcnkiLAogICAgICBzdHJfZGV0ZWN0KGRlc2NfYWxsLCAibWV4aWNhbnx0YWNvIikgfiAiTWV4aWNhbiIsCiAgICAgIHN0cl9kZXRlY3QoZGVzY19hbGwsICJjaGluZXNlIikgfiAiQ2hpbmVzZSIsCiAgICAgIHN0cl9kZXRlY3QoZGVzY19hbGwsICJzYW5kd2ljaHxkZWxpfHN1YiIpIH4gIlNhbmR3aWNoL0RlbGkiLAogICAgICBzdHJfZGV0ZWN0KGRlc2NfYWxsLCAiYmFyfHRhdmVybnxwdWIiKSB+ICJCYXIvUHViIiwKICAgICAgc3RyX2RldGVjdChkZXNjX2FsbCwgInJlc3RhdXJhbnR8YW1lcmljYW4iKSB+ICJSZXN0YXVyYW50IChHZW5lcmFsKSIsCiAgICAgIHN0cl9kZXRlY3QoZGVzY19hbGwsICJzY2hvb2x8Z3JvY2VyeXxtYXJrZXR8Y2F0ZXJlcnxraXRjaGVuIikgfiAiT3RoZXIgKEdyb2NlcnkvU2Nob29sL0V0Yy4pIiwKICAgICAgVFJVRSB+ICJPdGhlciIKICAgICkKICApCgojQ2hlY2sgbmV3IGNhdGVnb3JpZXMKaW5zcGVjdGlvbnNfY2F0ZWdvcml6ZWQgfD4KICBjb3VudChyZXN0YXVyYW50X2NhdGVnb3J5LCBzb3J0ID0gVFJVRSkKYGBgCgojIyMgVmlvbGF0aW9uICJGaW5nZXJwcmludCIgUGxvdApgYGB7ciBWaW9sYXRpb24gIkZpbmdlcnByaW50IiBQbG90fQojU3VtbWFyeSB0YWJsZQp2aW9sYXRpb25fZmluZ2VycHJpbnQgPC0gaW5zcGVjdGlvbnNfY2F0ZWdvcml6ZWQgfD4KICBmaWx0ZXIoCiAgICByZXN0YXVyYW50X2NhdGVnb3J5ICE9ICJPdGhlciIsCiAgICByZXN0YXVyYW50X2NhdGVnb3J5ICE9ICJPdGhlciAoR3JvY2VyeS9TY2hvb2wvRXRjLikiLAogICAgdmlvbGF0aW9uX2NhdGVnb3J5ICE9ICJPdGhlciIKICApIHw+CiAgY291bnQocmVzdGF1cmFudF9jYXRlZ29yeSwgdmlvbGF0aW9uX2NhdGVnb3J5KSB8PgogIGdyb3VwX2J5KHJlc3RhdXJhbnRfY2F0ZWdvcnkpIHw+CiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gc3VtKG4pKSB8PgogIHVuZ3JvdXAoKQoKIyBQbG90IHRoZSAiZmluZ2VycHJpbnQiCmdncGxvdCh2aW9sYXRpb25fZmluZ2VycHJpbnQsIAogICAgICAgYWVzKHggPSB2aW9sYXRpb25fY2F0ZWdvcnksIHkgPSBwcm9wb3J0aW9uLCBmaWxsID0gdmlvbGF0aW9uX2NhdGVnb3J5KSkgKwogIGdlb21fY29sKCkgKwogIGZhY2V0X3dyYXAofiByZXN0YXVyYW50X2NhdGVnb3J5KSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9wZXJjZW50KCkpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiVmlvbGF0aW9uICdGaW5nZXJwcmludCcgYnkgUmVzdGF1cmFudCBDYXRlZ29yeSIsCiAgICB5ID0gIlByb3BvcnRpb24gb2YgQWxsIFZpb2xhdGlvbnMiLAogICAgeCA9ICJWaW9sYXRpb24gVHlwZSIsCiAgICBmaWxsID0gIlZpb2xhdGlvbiBDYXRlZ29yeSIKICApCmBgYAoKUmVzdGF1cmFudCBjYXRlZ29yaWVzIGRvIGRpc3Byb3BvcnRpb25hdGVseSByZWNlaXZlIGNlcnRhaW4gdmlvbGF0aW9uIHR5cGVzLiBXaGlsZSAiU2FuaXRhdGlvbiAmIENsZWFuaW5nIiBpcyBhIHVuaXZlcnNhbCBwcm9ibGVtLCBzcGVjaWZpYyBtb2RlbHMgY2FycnkgdW5pcXVlIHJpc2tzLiAKVGhlIG1vc3QgaW1wb3J0YW50IHRha2Vhd2F5IGlzIHRoYXQgU2FuaXRhdGlvbiAmIENsZWFuaW5nIChwaW5rKSBhbmQgUGVzdCBDb250cm9sIChibHVlKSBhcmUgdGhlIHR3byBsYXJnZXN0IHZpb2xhdGlvbiBjYXRlZ29yaWVzIGFjcm9zcyBuZWFybHkgYWxsIHJlc3RhdXJhbnQgdHlwZXMuIEhvd2V2ZXIsIHRoZSBwcm9wb3J0aW9uIG9mIG90aGVyIGtleSBjYXRlZ29yaWVzIHJldmVhbHMgaW1wb3J0YW50IGRpZmZlcmVuY2VzOgoKUGVzdCBDb250cm9sIERvbWluYW5jZToKClN1c2hpL0phcGFuZXNlLCBTYW5kd2ljaC9EZWxpLCBhbmQgQmFyL1B1YnMgaGF2ZSB0aGUgaGlnaGVzdCBwcm9wb3J0aW9uIG9mIFBlc3QgQ29udHJvbCB2aW9sYXRpb25zLCBjb25zaXN0ZW50bHkgbWFraW5nIHVwIG92ZXIgMjUlIG9mIHRoZWlyIHRvdGFsIGlzc3Vlcy4KClNhbml0YXRpb24gJiBDbGVhbmluZyBGb2N1czoKCkNvZmZlZS9CYWtlcnksIFBpenphLCBhbmQgQ2hpbmVzZSByZXN0YXVyYW50cyBhcmUgaGlnaGx5IGRvbWluYXRlZCBieSBTYW5pdGF0aW9uICYgQ2xlYW5pbmcgdmlvbGF0aW9ucyAocGluayksIHdpdGggdGhpcyBjYXRlZ29yeSBvZnRlbiBleGNlZWRpbmcgNDAlIG9mIHRoZWlyIHRvdGFsIHZpb2xhdGlvbnMuCgpGb29kIFRlbXBlcmF0dXJlIFJpc2sgKFRoZSBPdXRsaWVyKToKClJlc3RhdXJhbnQgKEdlbmVyYWwpIGlzIHRoZSBvbmx5IGNhdGVnb3J5IHdoZXJlIEZvb2QgVGVtcGVyYXR1cmUgKHRlYWwpIG1ha2VzIHVwIHRoZSBsYXJnZXN0IG5vbi1TYW5pdGF0aW9uL1Blc3Qgc2hhcmUsIGhpdHRpbmcgYXBwcm94aW1hdGVseSAyNeKAkzMwJSBvZiBpdHMgdmlvbGF0aW9ucy4gVGhpcyBzdWdnZXN0cyB0aGF0IGJ1c2luZXNzZXMgd2l0aCBkaXZlcnNlIG1lbnVzIGFuZCBjb21wbGV4IGNvb2tpbmcgcHJvY2Vzc2VzIGFyZSB1bmlxdWVseSBwcm9uZSB0byB0ZW1wZXJhdHVyZS1yZWxhdGVkIGZhaWx1cmVzLgoKQ3Jvc3MtQ29udGFtaW5hdGlvbiBSaXNrOgoKTWV4aWNhbiBhbmQgU2FuZHdpY2gvRGVsaSByZXN0YXVyYW50cyBzaG93IGEgc2xpZ2h0bHkgZWxldmF0ZWQgcHJvcG9ydGlvbmFsIHJpc2sgZm9yIENyb3NzLUNvbnRhbWluYXRpb24gKHJlZCksIG9mdGVuIHJlbGF0ZWQgdG8gdGhlIGhpZ2ggdm9sdW1lIG9mIHJhdyBwcmVwYXJhdGlvbiAoZS5nLiwgY3V0dGluZyB2ZWdldGFibGVzLCBwcmVwYXJpbmcgc2Fsc2FzLCBoYW5kbGluZyBkZWxpIG1lYXRzKS4KCiMjIyBTdGFuZGFyZGl6ZSBJbnNwZWN0aW9uIFR5cGVzCmBgYHtyIFN0YW5kYXJkaXplIEluc3BlY3Rpb24gVHlwZXN9Cmluc3BlY3Rpb25zX2NhdGVnb3JpemVkIDwtIGluc3BlY3Rpb25zX2NhdGVnb3JpemVkIHw+CiAgbXV0YXRlKAogICAgdHlwZV9sb3dlciA9IHRvbG93ZXIoaW5zcGVjdGlvbl90eXBlKSwKICAgIAogICAgaW5zcGVjdGlvbl90eXBlX3N0YW5kYXJkID0gY2FzZV93aGVuKAogICAgICAjIEtleXdvcmRzIGZvciBjb21wbGFpbnQKICAgICAgc3RyX2RldGVjdCh0eXBlX2xvd2VyLCAiY29tcGxhaW50fDMxMXxvd25lciBjb21wbGFpbnQiKSB+ICJDb21wbGFpbnQiLAogICAgICAKICAgICAgIyBLZXl3b3JkcyBmb3Igcm91dGluZQogICAgICBzdHJfZGV0ZWN0KHR5cGVfbG93ZXIsICJyb3V0aW5lfGN5Y2xlfGNhbnZhc3N8cmVndWxhciIpIH4gIlJvdXRpbmUiLAogICAgICAKICAgICAgIyBLZXl3b3JkcyBmb3IgZm9sbG93LXVwcwogICAgICBzdHJfZGV0ZWN0KHR5cGVfbG93ZXIsICJyZS1pbnNwZWN0aW9ufHJlaW5zcGVjdGlvbnxmb2xsb3ctdXAiKSB+ICJGb2xsb3ctVXAiLAogICAgICAKICAgICAgVFJVRSB+ICJPdGhlciIKICAgICkKICApCgojbmV3IHN0YW5kYXJkaXplZCBjYXRlZ29yaWVzCmluc3BlY3Rpb25zX2NhdGVnb3JpemVkIHw+CiAgY291bnQoaW5zcGVjdGlvbl90eXBlX3N0YW5kYXJkLCBzb3J0ID0gVFJVRSkKYGBgCgojIyMgUGxvdCBTZXZlcml0eSBieSBJbnNwZWN0aW9uIFR5cGUKYGBge3IgUGxvdCBTZXZlcml0eSBieSBJbnNwZWN0aW9uIFR5cGV9CgppbnNwZWN0aW9uc19jYXRlZ29yaXplZCB8PgogICMgMS4gRmlsdGVyIHRoZSBkYXRhIChObyBjaGFuZ2VzIG5lZWRlZCBoZXJlKQogIGZpbHRlcigKICAgIGluc3BlY3Rpb25fdHlwZV9zdGFuZGFyZCAlaW4lIGMoIlJvdXRpbmUiLCAiQ29tcGxhaW50IiksCiAgICByaXNrX2xldmVsX3N0YW5kYXJkICE9ICJVbmtub3duIgogICkgfD4gIyA8LS0tIFBJUEUgVE8gVEhFIE5FWFQgU1RFUAogIAogICMgMi4gTXV0YXRlIChDb252ZXJ0IHRvIEZhY3RvcikKICBtdXRhdGUoCiAgICByaXNrX2xldmVsX3N0YW5kYXJkID0gZmFjdG9yKAogICAgICByaXNrX2xldmVsX3N0YW5kYXJkLCAKICAgICAgIyBTZXQgdGhlIGRlc2lyZWQgaGllcmFyY2hpY2FsIG9yZGVyCiAgICAgIGxldmVscyA9IGMoIkhpZ2giLCAiTWVkaXVtIiwgIkxvdyIpLAogICAgICBvcmRlcmVkID0gVFJVRQogICAgKQogICkgfD4gIyA8LS0tIENPUlJFQ1QgUElQRSBQTEFDRU1FTlQgKE91dHNpZGUgdGhlIGZpbmFsIG11dGF0ZSBwYXJlbnRoZXNpcykKICAKICAjIDMuIFBsb3QgcHJvcG9ydGlvbnMKICBnZ3Bsb3QoYWVzKHggPSBpbnNwZWN0aW9uX3R5cGVfc3RhbmRhcmQsIGZpbGwgPSByaXNrX2xldmVsX3N0YW5kYXJkKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bGFiZWxfcGVyY2VudCgpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArCiAgbGFicygKICAgIHRpdGxlID0gIlZpb2xhdGlvbiBTZXZlcml0eSBieSBJbnNwZWN0aW9uIFR5cGUiLAogICAgeCA9ICJJbnNwZWN0aW9uIFR5cGUiLAogICAgeSA9ICJQcm9wb3J0aW9uIG9mIFZpb2xhdGlvbnMiLAogICAgZmlsbCA9ICJSaXNrIExldmVsIgogICkKYGBgCgpUaGUgcHJvcG9ydGlvbmFsIHBsb3QgY2xlYXJseSBzaG93cyB0aGF0IENvbXBsYWludC1Ecml2ZW4gaW5zcGVjdGlvbnMgYXJlIG1vcmUgbGlrZWx5IHRvIGZpbmQgc2V2ZXJlIHByb2JsZW1zIHRoYW4gUm91dGluZSBpbnNwZWN0aW9uczEyLiBUaGUgcHJvcG9ydGlvbiBvZiBIaWdoIFJpc2sgdmlvbGF0aW9ucyBpcyB2aXN1YWxseSBsYXJnZXIgaW4gdGhlIENvbXBsYWludCBjb2x1bW4gdGhhbiBpbiB0aGUgUm91dGluZSBjb2x1bW4xMy4gVGhpcyBzdWdnZXN0cyB0aGUgcHVibGljIGlzIGVmZmVjdGl2ZSBhdCByZXBvcnRpbmcgcmVzdGF1cmFudHMgdGhhdCBwb3NlIGFuIGltbWVkaWF0ZSBwdWJsaWMgaGVhbHRoIHJpc2suCgojIyBQbG90IFZpb2xhdGlvbiBUeXBlIGJ5IEluc3BlY3Rpb24gVHlwZQpgYGB7ciBQbG90IFZpb2xhdGlvbiBUeXBlIGJ5IEluc3BlY3Rpb24gVHlwZX0KaW5zcGVjdGlvbnNfY2F0ZWdvcml6ZWQgfD4KICBmaWx0ZXIoCiAgICBpbnNwZWN0aW9uX3R5cGVfc3RhbmRhcmQgJWluJSBjKCJSb3V0aW5lIiwgIkNvbXBsYWludCIpLAogICAgdmlvbGF0aW9uX2NhdGVnb3J5ICE9ICJPdGhlciIgIyBSZW1vdmUgJ090aGVyJyB2aW9sYXRpb25zCiAgKSB8PgogIAogICMgUGxvdCBwcm9wb3J0aW9ucwogIGdncGxvdChhZXMoeCA9IGluc3BlY3Rpb25fdHlwZV9zdGFuZGFyZCwgZmlsbCA9IHZpb2xhdGlvbl9jYXRlZ29yeSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWaW9sYXRpb24gVHlwZXMgYnkgSW5zcGVjdGlvbiBUeXBlIiwKICAgIHggPSAiSW5zcGVjdGlvbiBUeXBlIiwKICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBWaW9sYXRpb25zIiwKICAgIGZpbGwgPSAiVmlvbGF0aW9uIENhdGVnb3J5IgogICkgKwogIGNvb3JkX2ZsaXAoKSAjIEZsaXAgYXhlcyB0byBtYWtlIGNhdGVnb3JpZXMgZWFzaWVyIHRvIHJlYWQKYGBgCgpXaGVuIGxvb2tpbmcgYXQgdmlvbGF0aW9uIHR5cGUsIENvbXBsYWludCBpbnNwZWN0aW9ucyBhcmUgZGlzcHJvcG9ydGlvbmF0ZWx5IGZvY3VzZWQgb24gUGVzdCBDb250cm9sIGFuZCBGb29kIFRlbXBlcmF0dXJlIGlzc3Vlcy4gSW4gY29udHJhc3QsIFJvdXRpbmUgaW5zcGVjdGlvbnMgZmluZCBhIG11Y2ggaGlnaGVyIHByb3BvcnRpb24gb2YgU2FuaXRhdGlvbiAmIENsZWFuaW5nIGFuZCBGYWNpbGl0eS9NYWludGVuYW5jZSBwcm9ibGVtcy4gVGhpcyBzdWdnZXN0cyB0aGF0IHBhdHJvbnMgYXJlIHF1aWNrIHRvIHJlcG9ydCB2aXNpYmxlIHNpZ25zIG9mIHBlc3RzIG9yIHRlbXBlcmF0dXJlIGlzc3Vlcywgd2hpbGUgaW5zcGVjdG9ycyBmaW5kIG1vcmUgc3RydWN0dXJhbC9oeWdpZW5lIHByb2JsZW1zIGR1cmluZyB1bmFubm91bmNlZCwgY29tcHJlaGVuc2l2ZSBjaGVja3MuCgpPdXIgYW5hbHlzaXMgY29uZmlybXMgdHdvIGNyaXRpY2FsIHJlbGF0aW9uc2hpcHM6CgoxLiAgKipCdXNpbmVzcyBNb2RlbCBSaXNrOioqIFRoZSB0eXBlIG9mIGN1aXNpbmUgYSByZXN0YXVyYW50IHNlcnZlcyBjcmVhdGVzIGEgdW5pcXVlICJmaW5nZXJwcmludCIgb2YgaGVhbHRoIHJpc2tzIChRMSkuIENvbXBsZXggY29va2luZyAoUmVzdGF1cmFudCBHZW5lcmFsKSBjb3JyZWxhdGVzIHdpdGggKipGb29kIFRlbXBlcmF0dXJlKiogaXNzdWVzLCB3aGlsZSBoaWdoLXZvbHVtZSByYXcgcHJlcGFyYXRpb24gKFN1c2hpL0RlbGkpIGNvcnJlbGF0ZXMgd2l0aCAqKlBlc3QgQ29udHJvbCoqIGFuZCAqKkNyb3NzLUNvbnRhbWluYXRpb24qKi4KMi4gICoqSW5zcGVjdGlvbiBUeXBlIEJpYXM6KiogUHVibGljIGNvbXBsYWludHMgKFEyKSBhcmUgaGlnaGx5IGVmZmVjdGl2ZSBhdCBmbGFnZ2luZyBpbW1lZGlhdGUgcHVibGljIGhlYWx0aCB0aHJlYXRzLCBkZW1vbnN0cmF0aW5nIGEgaGlnaGVyIHByb3BvcnRpb25hbCBpbmNpZGVuY2Ugb2YgKipIaWdoIFJpc2sqKiB2aW9sYXRpb25zIGFuZCAqKlBlc3QgQ29udHJvbCoqIHByb2JsZW1zIGNvbXBhcmVkIHRvIHJvdXRpbmUgaW5zcGVjdGlvbnMu